package gu.sql2java;
import java.util.List;

import com.google.common.base.Function;

import gu.sql2java.exception.ObjectRetrievalException;
import gu.sql2java.exception.RuntimeDaoException;
import gu.sql2java.geometry.GeometryDataCodec;

import java.util.Collection;
/**
 * Interface to handle database calls (save, load, count, etc...) for table.
 * @author guyadong
 */
public interface TableManager<B extends BaseBean> extends SqlRunner{

    public interface Action<B>{

        /**
         * do action for {@code bean}
         * @param bean input bean
         */
        void call(B bean);
    }
	/**
	 * interface for iterate
	 */
	public interface DoEach<B>{
		/**
		 * do action for {@code bean}<br>
		 * <b>NOTE:</b><br>DO NOT run  deletion operation in the method
		 * @param bean
		 * @return remove the row if {@code true}
		 * @throws Exception 
		 */
		boolean doEach(B bean) throws Exception;
	}
    /**
	 * Creates a new B instance.
	 *
	 * @return the new B instance
	 */
	public B createBean();

	//_____________________________________________________________________
    //
    // COUNT
    //_____________________________________________________________________
    //24
    /**
     * Retrieves the number of rows of the table.
     *
     * @return the number of rows returned
     * @throws RuntimeDaoException
     */
    public int countAll()throws RuntimeDaoException;
    
    //27
    /**
     * count the number of elements of a specific bean
     *
     * @param bean the bean to look for ant count
     * @return the number of rows returned
     * @throws RuntimeDaoException
     */
    public int countUsingTemplate( B bean)throws RuntimeDaoException;
  
    //20
    /**
     * count the number of elements of a specific bean given the search type
     *
     * @param bean the template to look for
     * @param searchType exact ?  like ? starting like ? ending link ? <br>
     *                {@value gu.sql2java.Constant#SEARCH_EXACT}   {@link Constant#SEARCH_EXACT} <br>
     *                {@value gu.sql2java.Constant#SEARCH_LIKE}   {@link Constant#SEARCH_LIKE} <br>
     *                {@value gu.sql2java.Constant#SEARCH_STARTING_LIKE}   {@link Constant#SEARCH_STARTING_LIKE} <br>
     *                {@value gu.sql2java.Constant#SEARCH_ENDING_LIKE}   {@link Constant#SEARCH_ENDING_LIKE} <br>  
     * @return the number of rows returned
     * @throws RuntimeDaoException
     */
    public int countUsingTemplate(B bean, int searchType)throws RuntimeDaoException;

    //25
    /**
     * Retrieves the number of rows of the table with a 'where' clause.
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param where the restriction clause
     * @return the number of rows returned
     * @throws RuntimeDaoException
     */
    public int countWhere(String where)throws RuntimeDaoException;

  //25-1
    /**
     * Retrieves the number of rows of the table with a 'where' clause.
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param where the restriction clause
     * @param argList  the arguments to use fill given prepared statement,may be null
     * @return the number of rows returned
     * @throws RuntimeDaoException
     */
	public int rowCountWhere(String where, Object... argList)throws RuntimeDaoException;

    //10
    /**
     * Deletes all rows from table.
     * @return the number of deleted rows.
     * @throws RuntimeDaoException
     */
    public int deleteAll()throws RuntimeDaoException;

    //11
    /**
     * Deletes rows from the table using a 'where' clause.
     * It is up to you to pass the 'WHERE' in your where clauses.
     * <br>Attention, if 'WHERE' is omitted it will delete all records.
     *
     * @param where the sql 'where' clause
     * @return the number of deleted rows
     * @throws RuntimeDaoException
     */
    public int deleteByWhere(String where)throws RuntimeDaoException;

    //21
    /**
     * Deletes rows using a template.
     *
     * @param bean the template object(s) to be deleted
     * @return the number of deleted objects
     * @throws RuntimeDaoException
     */
    public int deleteUsingTemplate(B bean)throws RuntimeDaoException;

    //2.1
    /**
     * Delete row according to its primary keys.
     *
     * @param keys primary keys value<br>
     *      for fd_face table<br>
     *          PK# 1 fd_face.id type Integer<br>
     *      for fd_feature table<br>
     *          PK# 1 fd_feature.md5 type String<br>
     *      for fd_image table<br>
     *          PK# 1 fd_image.md5 type String<br>
     *      for fd_store table<br>
     *          PK# 1 fd_store.md5 type String<br>
     * @return the number of deleted rows
     * @throws RuntimeDaoException
     */   
    public int deleteByPrimaryKey(Object ...keys)throws RuntimeDaoException;

    //2.2
    /**
     * Delete row according to primary keys of bean.<br>
     * 
     * @param bean will be deleted ,all keys must not be null
     * @return the number of deleted rows,0 returned if bean is null
     * @throws RuntimeDaoException
     */
    public int delete(B bean)throws RuntimeDaoException;

    //2.4
	/**
	 * Delete beans.<br>
	 *
	 * @param beans B array will be deleted
	 * @return the number of deleted rows
	 * @throws RuntimeDaoException
	 */
    @SuppressWarnings("unchecked")
	public int delete(B... beans)throws RuntimeDaoException;
    
    //2.5  
  	/**
  	 * Delete beans.<br>
  	 *
  	 * @param beans B collection will be deleted
  	 * @return the number of deleted rows
  	 * @throws RuntimeDaoException
  	 */
  	public int delete(Collection<B> beans)throws RuntimeDaoException;
  	/**
  	 * set a value to the given field in bean if the given field of old record in database is not null
  	 * @param bean
  	 * @param column column name
  	 * @param value
  	 * @return true if not equal with old record in database,otherwise false
  	 * @since 3.15.4
  	 */
  	public boolean setValueIfNonNull(B bean, String column, Object value);
  	/**
  	 * set a value to the given field in bean if value is not equal to the given field of old record in database
  	 * @param bean
  	 * @param column column name
  	 * @param value
  	 * @return true if not equal with old record in database,otherwise false
  	 * @since 3.15.4
  	 */
  	public boolean setValueIfNonEqual(B bean, String column, Object value);
    //////////////////////////////////////
    // LOAD ALL
    //////////////////////////////////////


    //5
    /**
     * Loads all the rows from table.
     *
     * @return an array of B bean
     * @throws RuntimeDaoException
     */
    public B[] loadAll()throws RuntimeDaoException;

    //5-1    
    /**
     * Loads each row from table and dealt with action.
     * @param action  Action object for do something(not null)
     * @return the count dealt by action
     * @throws RuntimeDaoException
     */
    public int loadAll(Action<B> action)throws RuntimeDaoException;

    //6
    /**
     * Loads the given number of rows from table, given the start row.
     *
     * @param startRow the start row to be used (first row = 1, last row = -1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @return an array of B bean
     * @throws RuntimeDaoException
     */
    public B[] loadAll(int startRow, int numRows)throws RuntimeDaoException;

    //6-1    
    /**
     *  Loads the given number of rows from table, given the start row and dealt with action.
     * @param startRow the start row to be used (first row = 1, last row = -1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @param action  Action object for do something(not null)
     * @return the count dealt by action
     * @throws RuntimeDaoException
     */
    public int loadAll(int startRow, int numRows,Action<B> action)throws RuntimeDaoException;

    //5-2
    /**
     * Loads all the rows from table.
     *
     * @return a list of B bean
     * @throws RuntimeDaoException
     */
    public List<B> loadAllAsList()throws RuntimeDaoException;

    //6-2
    /**
     * Loads the given number of rows from table, given the start row.
     *
     * @param startRow the start row to be used (first row = 1, last row = -1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @return a list of B bean
     * @throws RuntimeDaoException
     */
    public List<B> loadAllAsList(int startRow, int numRows)throws RuntimeDaoException;

    //1.2
    /**
     * Loads a B bean from the table using primary key fields of {@code bean}.
     * @param bean the B bean with primary key fields
     * @return a unique B or {@code null} if not found or bean is null
     * @throws RuntimeDaoException
     */
    public B loadByPrimaryKey(B bean)throws RuntimeDaoException;
    
    //1.2.2
    /**
     * see also {@link #loadByPrimaryKey(BaseBean)} 
     * @param bean
     * @return a unique B ,otherwise throw exception
     * @throws ObjectRetrievalException not found
     * @throws RuntimeDaoException
     */
    public B loadByPrimaryKeyChecked(B bean)throws RuntimeDaoException,ObjectRetrievalException;
    //1.3
    /**
     * Loads a B bean from the table using primary key fields.
     * when you don't know which is primary key of table,you can use the method.
     * @param keys primary keys value:<br> 
     *      for fd_face table<br>
     *          PK# 1 fd_face.id type Integer<br>
     *      for fd_feature table<br>
     *          PK# 1 fd_feature.md5 type String<br>
     *      for fd_image table<br>
     *          PK# 1 fd_image.md5 type String<br>
     *      for fd_store table<br>
     *          PK# 1 fd_store.md5 type String<br>
     * @return a unique B or {@code null} if not found
     * @throws RuntimeDaoException
     */
    public B loadByPrimaryKey(Object ...keys)throws RuntimeDaoException;

    //1.3.2
    /**
     * see also {@link #loadByPrimaryKey(Object...)}
     * @param keys
     * @return a unique B,otherwise throw exception
     * @throws ObjectRetrievalException not found
     * @throws RuntimeDaoException
     */
    public B loadByPrimaryKeyChecked(Object ...keys)throws RuntimeDaoException,ObjectRetrievalException;
    
    //1.5
    /**
     * Returns true if this table contains row with primary key fields.
     * @param keys primary keys value
     * @see #loadByPrimaryKey(Object...)
     * @throws RuntimeDaoException
     */
    public boolean existsPrimaryKey(Object ...keys)throws RuntimeDaoException;
    
    //1.6
    /**
     * Returns true if this table contains row specified by primary key fields of B.<br>
     * when you don't know which is primary key of table,you can use the method.
     * @param bean the B bean with primary key fields
     * @see #loadByPrimaryKey(BaseBean)
     * @throws RuntimeDaoException
     */
    public boolean existsByPrimaryKey(B bean)throws RuntimeDaoException;
    //1.7
    /**
     * Check duplicated row by primary keys,if row exists throw exception
     * @param bean the B bean with primary key fields
     * @return always bean
     * @see #existsByPrimaryKey(BaseBean)
     * @throws ObjectRetrievalException has duplicated record
     * @throws RuntimeDaoException
     */
    public B checkDuplicate(B bean)throws RuntimeDaoException,ObjectRetrievalException;
   
    //////////////////////////////////////
    // SQL 'WHERE' METHOD
    //////////////////////////////////////
    //7 
    /**
     * Retrieves an array of B given a sql 'where' clause.
     *
     * @param where the sql 'where' clause
     * @throws RuntimeDaoException
     */
    public B[] loadByWhere(String where)throws RuntimeDaoException;
    //7-2
    /**
     * Retrieves each row of B bean given a sql 'where' clause and dealt with action.
     * @param where the sql 'where' clause
     * @param action  Action object for do something(not null)
     * @return the count dealt by action
     * @throws RuntimeDaoException
     */
    public int loadByWhere(String where,Action<B> action)throws RuntimeDaoException;
    //8
    /**
     * Retrieves an array of B bean given a sql where clause, and a list of fields.
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param where the sql 'WHERE' clause
     * @param fieldList array of field's ID
     * @throws RuntimeDaoException
     */
    public B[] loadByWhere(String where, int[] fieldList)throws RuntimeDaoException;
    //8-2
    /**
     * Retrieves each row of B bean given a sql where clause, and a list of fields,
     * and dealt with action.
     * It is up to you to pass the 'WHERE' in your where clauses.
     * @param where the sql 'WHERE' clause
     * @param fieldList array of field's ID
     * @param action Action object for do something(not null)
     * @return the count dealt by action
     * @throws RuntimeDaoException
     */
    public int loadByWhere(String where, int[] fieldList,Action<B> action)throws RuntimeDaoException;
    //9
    /**
     * Retrieves an array of B bean given a sql where clause and a list of fields, and startRow and numRows.
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param where the sql 'where' clause
     * @param fieldList table of the field's associated constants
     * @param startRow the start row to be used (first row = 1, last row = -1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @throws RuntimeDaoException
     */
    public B[] loadByWhere(String where, int[] fieldList, int startRow, int numRows)throws RuntimeDaoException;
    //9-2
    /**
     * Retrieves each row of B bean given a sql where clause and a list of fields, and startRow and numRows,
     * and dealt with action.
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param where the sql 'where' clause
     * @param fieldList table of the field's associated constants
     * @param startRow the start row to be used (first row = 1, last row = -1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @param action Action object for do something(not null)
     * @return the count dealt by action
     * @throws RuntimeDaoException
     */
    public int loadByWhere(String where, int[] fieldList, int startRow, int numRows,Action<B> action)throws RuntimeDaoException;
    //7-4
    /**
     * Retrieves a list of B bean given a sql 'where' clause.
     *
     * @param where the sql 'where' clause
     * @throws RuntimeDaoException
     */
    public List<B> loadByWhereAsList(String where)throws RuntimeDaoException;
    //7-5
    /**
     * Retrieves a list of B bean given a sql 'where' clause.
     *
     * @param join the sql 'join' clause
     * @param where the sql 'where' clause
     * @throws RuntimeDaoException
     */
    public List<B> loadByJoinWhereAsList(String join,String where)throws RuntimeDaoException;

    //8-4
    /**
     * Retrieves a list of B bean given a sql where clause, and a list of fields.
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param where the sql 'WHERE' clause
     * @param fieldList array of field's ID
     * @throws RuntimeDaoException
     */
    public List<B> loadByWhereAsList(String where, int[] fieldList)throws RuntimeDaoException;
    //8-5
    /**
     * Retrieves a list of B bean given a sql where clause, and a list of fields.
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param join the sql 'join' clause
     * @param where the sql 'WHERE' clause
     * @param argList the arguments to use fill given prepared statement,may be null
     * @param fieldList array of field's ID
     * @throws RuntimeDaoException
     */
    public List<B> loadByJoinWhereAsList(String join,String where, Object[] argList, int[] fieldList)throws RuntimeDaoException;
    
    //9-4
    /**
     * Retrieves a list of B bean given a sql where clause and a list of fields, and startRow and numRows.
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param where the sql 'where' clause
     * @param fieldList table of the field's associated constants
     * @param startRow the start row to be used (first row = 1, last row = -1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @throws RuntimeDaoException
     */
    public List<B> loadByWhereAsList(String where, int[] fieldList, int startRow, int numRows)throws RuntimeDaoException;
    //9-5
    /**
     * Retrieves a list of B bean given a sql where clause and a list of fields, and startRow and numRows.
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param join the sql 'join' clause
     * @param where the sql 'where' clause
     * @param fieldList table of the field's associated constants
     * @param startRow the start row to be used (first row = 1, last row = -1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @throws RuntimeDaoException
     */
    public List<B> loadByJoinWhereAsList(String join,String where, int[] fieldList, int startRow, int numRows)throws RuntimeDaoException;

    //9-5
    /**
     * Retrieves a list of T bean given a sql where clause and a list of fields, and startRow and numRows.
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param join the sql 'join' clause
     * @param where the sql 'where' clause
     * @param argList the arguments to use fill given prepared statement,may be null
     * @param fieldList table of the field's associated constants
     * @param startRow the start row to be used (first row = 1, last row = -1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @param transformer cast B to T
     * @throws RuntimeDaoException
     */
    public <T> List<T> loadByJoinWhereAsList(String join, String where, Object[] argList, int[] fieldList, int startRow, int numRows,
    Function<B, T>transformer) throws RuntimeDaoException;

    //9-6
    /**
     * Retrieves each row of B bean given a sql where clause and a list of fields, and startRow and numRows,
     * and dealt wity action
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param where the sql 'where' clause
     * @param argList the arguments to use fill given prepared statement,may be null
     * @param fieldList table of the field's associated constants
     * @param startRow the start row to be used (first row = 1, last row = -1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @param action Action object for do something(not null)
     * @return the count dealt by action
     * @throws RuntimeDaoException
     */
    public int loadByWhereForAction(String where, Object[] argList, int[] fieldList, int startRow,int numRows, Action<B> action)throws RuntimeDaoException;
    //9-7
    /**
     * Retrieves each row of B bean given a sql where clause and a list of fields, and startRow and numRows,
     * and dealt with action.
     * It is up to you to pass the 'WHERE' in your where clauses.
     *
     * @param join the sql 'join' clause
     * @param where the sql 'where' clause
     * @param argList the arguments to use fill given prepared statement,may be null
     * @param fieldList table of the field's associated constants
     * @param startRow the start row to be used (first row = 1, last row = -1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @param action Action object for do something(not null)
     * @return the count dealt by action
     * @throws RuntimeDaoException
     */
    public int loadByJoinWhereForAction(String join,String where, Object[] argList, int[] fieldList, int startRow,int numRows, Action<B> action)throws RuntimeDaoException;

    //_____________________________________________________________________
    //
    // USING TEMPLATE
    //_____________________________________________________________________
    //18   
    /**
     * Loads a unique B bean from a template one giving a c
     *
     * @param bean the B bean to look for
     * @return the bean matching the template,or {@code null} if not found or null input argument
     * @throws ObjectRetrievalException more than one row
     * @throws RuntimeDaoException
     */
    public B loadUniqueUsingTemplate(B bean)throws RuntimeDaoException;

    //18-1
    /**
     * Loads a unique B bean from a template one giving a c
     *
     * @param bean the B bean to look for
     * @return the bean matching the template
     * @throws ObjectRetrievalException not found or more than one row
     * @throws RuntimeDaoException
     */
    public B loadUniqueUsingTemplateChecked(B bean)throws RuntimeDaoException,ObjectRetrievalException;

    //19
    /**
     * Loads an array of B from a template one.
     *
     * @param bean the B bean template to look for
     * @return all the B beans matching the template
     * @throws RuntimeDaoException
     */
    public B[] loadUsingTemplate(B bean)throws RuntimeDaoException;
    
    //19-1
    /**
     * Loads each row from a template one and dealt with action.
     *
     * @param bean the B bean template to look for
     * @param action Action object for do something(not null)
     * @return the count dealt by action
     * @throws RuntimeDaoException
     */
    public int loadUsingTemplate(B bean,Action<B> action)throws RuntimeDaoException;

    //20
    /**
     * Loads an array of B bean from a template one, given the start row and number of rows.
     *
     * @param bean the B bean template to look for
     * @param startRow the start row to be used (first row = 1, last row=-1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @return all the B matching the template
     * @throws RuntimeDaoException
     */
    public B[] loadUsingTemplate(B bean, int startRow, int numRows)throws RuntimeDaoException;
    
    //20-1
    /**
     * Loads each row from a template one, given the start row and number of rows and dealt with action.
     *
     * @param bean the B bean template to look for
     * @param startRow the start row to be used (first row = 1, last row=-1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @param action Action object for do something(not null)
     * @return the count dealt by action
     * @throws RuntimeDaoException
     */
    public int loadUsingTemplate(B bean, int startRow, int numRows,Action<B> action)throws RuntimeDaoException;

    //20-5
    /**
     * Loads each row from a template one, given the start row and number of rows and dealt with action.
     *
     * @param bean the B template to look for
     * @param fieldList table of the field's associated constants
     * @param startRow the start row to be used (first row = 1, last row=-1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @param searchType exact ?  like ? starting like ? ending link ? <br>
     *                {@value gu.sql2java.Constant#SEARCH_EXACT}   {@link Constant#SEARCH_EXACT} <br>
     *                {@value gu.sql2java.Constant#SEARCH_LIKE}   {@link Constant#SEARCH_LIKE} <br>
     *                {@value gu.sql2java.Constant#SEARCH_STARTING_LIKE}   {@link Constant#SEARCH_STARTING_LIKE} <br>
     *                {@value gu.sql2java.Constant#SEARCH_ENDING_LIKE}   {@link Constant#SEARCH_ENDING_LIKE} <br>  
     * @param action Action object for do something(not null)
     * @return the count dealt by action
     * @throws RuntimeDaoException
     */
    public int loadUsingTemplate(B bean, int[] fieldList, int startRow, int numRows,int searchType, Action<B> action)throws RuntimeDaoException;
    //20-4
    /**
     * Loads a list of B bean from a template one, given the start row and number of rows.
     *
     * @param bean the B bean template to look for
     * @param startRow the start row to be used (first row = 1, last row=-1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @param searchType exact ?  like ? starting like ? ending link ? <br>
     *                {@value gu.sql2java.Constant#SEARCH_EXACT}   {@link Constant#SEARCH_EXACT} <br>
     *                {@value gu.sql2java.Constant#SEARCH_LIKE}   {@link Constant#SEARCH_LIKE} <br>
     *                {@value gu.sql2java.Constant#SEARCH_STARTING_LIKE}   {@link Constant#SEARCH_STARTING_LIKE} <br>
     *                {@value gu.sql2java.Constant#SEARCH_ENDING_LIKE}   {@link Constant#SEARCH_ENDING_LIKE} <br>  
     * @return all the B bean matching the template
     * @throws RuntimeDaoException
     */
    public B[] loadUsingTemplate(B bean, int startRow, int numRows, int searchType)throws RuntimeDaoException;

    //19-2
    /**
     * Loads a list of B bean from a template one.
     *
     * @param bean the B bean template to look for
     * @return all the B beans matching the template
     * @throws RuntimeDaoException
     */
    public List<B> loadUsingTemplateAsList(B bean)throws RuntimeDaoException;

    //20-2
    /**
     * Loads a list of B bean from a template one, given the start row and number of rows.
     *
     * @param bean the B bean template to look for
     * @param startRow the start row to be used (first row = 1, last row=-1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @return all the B bean matching the template
     * @throws RuntimeDaoException
     */
    public List<B> loadUsingTemplateAsList(B bean, int startRow, int numRows)throws RuntimeDaoException;

    //20-3
    /**
     * Loads an array of B bean from a template one, given the start row and number of rows.
     *
     * @param bean the B bean template to look for
     * @param startRow the start row to be used (first row = 1, last row=-1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @param searchType exact ?  like ? starting like ? ending link? <br>
     *                {@value gu.sql2java.Constant#SEARCH_EXACT}   {@link Constant#SEARCH_EXACT} <br>
     *                {@value gu.sql2java.Constant#SEARCH_LIKE}   {@link Constant#SEARCH_LIKE} <br>
     *                {@value gu.sql2java.Constant#SEARCH_STARTING_LIKE}   {@link Constant#SEARCH_STARTING_LIKE} <br>
     *                {@value gu.sql2java.Constant#SEARCH_ENDING_LIKE}   {@link Constant#SEARCH_ENDING_LIKE} <br>  
     * @return all the B beans matching the template
     * @throws RuntimeDaoException
     */
    public List<B> loadUsingTemplateAsList(B bean, int startRow, int numRows, int searchType)throws RuntimeDaoException;
    //20-4
    /**
     * Retrieves each row of B bean given a SQL where clause and a list of fields,
     * and dealt with each action.
     * It is up to you to pass the 'WHERE' in your where clauses.
     * @param each DoForEach object for do something(not null)
     * @param stopOnError stop on error
     * @param where the SQL 'where' clause, retrieves all rows if {@code null} or empty
     * @throws RuntimeDaoException
     */
    public void foreachByWhere(DoEach<B> each, boolean stopOnError, String where)throws RuntimeDaoException;
    //20-5
    /**
     * Retrieves each row of B bean given a SQL where clause and a list of fields,
     * and dealt with each action.
     * It is up to you to pass the 'WHERE' in your where clauses.
     * @param each DoForEach object for do something(not null)
     * @param stopOnError stop on error
     * @param join the sql 'join' clause
     * @param where the SQL 'where' clause, retrieves all rows if {@code null} or empty
     * @throws RuntimeDaoException
     */
    public void foreachByJoinWhere(DoEach<B> each, boolean stopOnError, String join, String where)throws RuntimeDaoException;
    //20-6
    /**
     * Retrieves each row of B bean given a SQL where clause and a list of fields,
     * and dealt with each action.
     * It is up to you to pass the 'WHERE' in your where clauses.
     * @param each DoForEach object for do something(not null)
     * @param stopOnError stop on error
     * @throws RuntimeDaoException
     */
    public void foreach(DoEach<B> each, boolean stopOnError)throws RuntimeDaoException;
    //_____________________________________________________________________
    //
    // LISTENER
    //_____________________________________________________________________

    //35
    /**
     * Registers a unique {@link TableListener} listener.<br>
     * do nothing if {@code TableListener} instance exists
     * @param listener
     */
    public void registerListener(TableListener<B> listener);

    //36
    /**
     * remove listener.
     * @param listener 
     */
    public void unregisterListener(TableListener<B> listener);

    //_____________________________________________________________________
    //
    // SAVE
    //_____________________________________________________________________
    //12
    /**
     * Saves the B bean into the database.
     *
     * @param bean the B bean to be saved
     * @return the inserted or updated bean,or null if bean is null
     * @throws RuntimeDaoException
     */
    public B save(B bean)throws RuntimeDaoException;

    //12-1
	/**
     * If the specified key is not already exist, add it to database.
     * This is equivalent to
     *  <pre> {@code
     * if (!existsByPrimaryKey(bean))
     *   return insert(bean);
     * else
     *   return loadByPrimaryKey(bean);
     * }</pre>
     *
     * except that the action is performed atomically .
	 * @param bean the B bean to be saved
     * @return the previous value exists in database, or saved bean if not exists bean ,
     * 				or {@code null} if bean is {@code null}
	 * @throws RuntimeDaoException
	 */
	public B addIfAbsent(B bean) throws RuntimeDaoException;
    //15
    /**
     * Saves an array of B bean into the database.
     *
     * @param beans the array of  B bean to be saved
     * @return always beans saved
     * @throws RuntimeDaoException
     */
    public B[] save(B[] beans)throws RuntimeDaoException;
    
    //15-2
    /**
     * Saves a collection of B bean into the database.
     *
     * @param beans the B bean table to be saved
     * @return alwarys beans saved
     * @throws RuntimeDaoException
     */
    public <C extends Collection<B>> C saveAsTransaction(C beans)throws RuntimeDaoException;
    
    //15-3
    /**
     * Saves an array of B bean into the database as transaction.
     *
     * @param beans the B bean table to be saved
     * @return alwarys beans saved
     * @see #save(BaseBean[])
     * @throws RuntimeDaoException
     */
    public B[] saveAsTransaction(B[] beans)throws RuntimeDaoException;

    //15-4
    /**
     * Saves a collection of B bean into the database as transaction.
     *
     * @param beans the B bean table to be saved
     * @return alwarys beans saved
     * @throws RuntimeDaoException
     */
    public <C extends Collection<B>> C save(C beans)throws RuntimeDaoException;
    /**
     * Insert the B bean list into the database.
     * no support {@link TableListener}
     * @param fieldList table of the field's associated constants,if null as all field 
     * @param beans the B bean list to be saved
     * @throws RuntimeDaoException
     * @since 3.15.4
     */
    <C extends Iterable<B>> void fastInsert(int[] fieldList, C beans);

    /**
     * Load column from table.
     * @param column column name or java file name of B
     * @param distinct select distinct values
     * @param where the sql 'where' clause
     * @param startRow the start row to be used (first row = 1, last row = -1)
     * @param numRows the number of rows to be retrieved (all rows = a negative number)
     * @return an list of column
     * @throws RuntimeDaoException
     */
    public <T>List<T> loadColumnAsList(String column,boolean distinct,String where,int startRow,int numRows)throws RuntimeDaoException;
    
    /**
     * @return ListenerContainer instance of current table manager
     */
    public ListenerContainer<B> getListenerContainer();

	/**
	 * @return data source information
	 */
	public IDataSourceConfig getDataSourceConfig();

	/**
	 * @return Geometry Data code/decode instance
	 * @since 3.18.0
	 */
	public GeometryDataCodec getGeometryDataCodec();
}
